package com.duobaoyu.dby.supply.api.service.impl;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.duobaoyu.dby.channel.adapter.enums.biz.config.GlobalErrorCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderTypeEnum;
import com.duobaoyu.dby.channel.common.util.SupplyCollectionUtils;
import com.duobaoyu.dby.common.core.constant.CommonConstants;
import com.duobaoyu.dby.common.core.util.StringUtil;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.api.converter.SupplyChainApiConverter;
import com.duobaoyu.dby.supply.api.service.OrderBizService;
import com.duobaoyu.dby.supply.api.service.rule.order.handler.LargeAmountOrderRule;
import com.duobaoyu.dby.supply.biz.client.boundary.order.OrderBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.*;
import com.duobaoyu.dby.supply.biz.client.product.ProductCenterApiClient;
import com.duobaoyu.dby.supply.biz.client.product.bean.bo.SkuInfoCheckBO;
import com.duobaoyu.dby.supply.biz.constant.OperateSourceConstants;
import com.duobaoyu.dby.supply.biz.constant.OrderOperateConstants;
import com.duobaoyu.dby.supply.biz.converter.OrderConverter;
import com.duobaoyu.dby.supply.biz.enums.OrderLevelEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.enums.OrderTagEnum;
import com.duobaoyu.dby.supply.biz.event.SalesVolumeStatistics;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainDelayMessageProducer;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainMQProducer;
import com.duobaoyu.dby.supply.biz.service.order.OrderProductService;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.service.rule.RuleService;
import com.duobaoyu.dby.supply.common.biz.bo.order.OrderSplitBO;
import com.duobaoyu.dby.supply.common.biz.bo.order.OrderStatusCheckBO;
import com.duobaoyu.dby.supply.common.biz.remote.dto.order.*;
import com.duobaoyu.dby.supply.common.biz.remote.to.order.CancelOrderTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.order.OrderDetailTO;
import com.duobaoyu.dby.supply.common.biz.remote.to.order.OrderTO;
import com.duobaoyu.dby.supply.core.common.exception.CustomAssert;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenms
 * @date 2023/9/27 2:26 PM
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderBizServiceImpl implements OrderBizService {

	private final OrderService orderService;
	private final OrderConverter orderConverter;
	private final ApplicationContext applicationContext;
	private final OrderBoundaryClient orderBoundaryClient;
	private final OrderProductService orderProductService;
	private final LargeAmountOrderRule largeAmountOrderRule;
	private final SupplyChainMQProducer supplyChainMQProducer;
	private final ProductCenterApiClient productCenterApiClient;
	private final SupplyChainApiConverter supplyChainApiConverter;
	private final SupplyChainDelayMessageProducer supplyChainDelayMessageProducer;

	@Override
	public OrderTO submitOrder(SubmitOrderDTO submitOrder) {
		//校验交易号是否重复
		orderService.tradeSnCheck(submitOrder.getBizTradeSn(), submitOrder.getMchId(), submitOrder.getShowServerName());

		//调用商品中心做本地商品校验
		SkuInfoCheckBO skuInfoCheck = productCenterApiClient.skuInfoCheck(submitOrder.getSkuInfos(), submitOrder.getShowServerName(), Boolean.TRUE);
		if (CollectionUtils.isNotEmpty(skuInfoCheck.getErrorSkuInfoList())) {
			//组装异常sku信息返回
			List<OrderTO.ErrorSkuInfo> errorSkuInfoList = orderConverter.toOrderErrorSkuInfoList(skuInfoCheck.getErrorSkuInfoList());
			return OrderTO.builder().success(Boolean.FALSE).errorSkuInfoList(errorSkuInfoList).build();
		}
		// 校验充值账号
		orderService.validRechargeAccount(submitOrder, skuInfoCheck.getSkuInfoList());
		OrderSplitBO orderSplit = orderBoundaryClient.orderSplit(submitOrder, skuInfoCheck);
		//校验是否为大额订单
		boolean execute = RuleService.create()
				.or(Lists.newArrayList(largeAmountOrderRule))
				.execute(supplyChainApiConverter.toOrderAsyncRule(skuInfoCheck));
		if (execute) {
			//大额订单直接入库
			String supplyTradeSn = orderService.largeOrderSave(orderSplit, submitOrder);
			return OrderTO.builder().success(Boolean.TRUE).supplyTradeSn(supplyTradeSn).build();
		}
		//进行预提交
		OrderSubmitBO orderSubmit = orderBoundaryClient.submitOrder(orderSplit, submitOrder.getOrderRemark());

		// 存在提交失败订单, 如果有错误商品返回错误商品,否则抛出异常
		if (CollectionUtils.isNotEmpty(orderSubmit.getErrorOrderList())) {
			List<OrderTO.ErrorSkuInfo> errorSkuInfoList = orderSubmit.getErrorOrderList().stream().filter(item -> CollectionUtils.isNotEmpty(item.getErrorSkuCode())).map(item -> item.getErrorSkuCode().stream().map(skuCode -> OrderTO.ErrorSkuInfo.builder().skuCode(skuCode).message(item.getErrorMessage()).state(item.getErrorCode()).build()).collect(Collectors.toList())).flatMap(Collection::stream).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(errorSkuInfoList)) {
				// 如果是渠道商品下架,下架商品
				List<String> offShelfSkuCodeList = errorSkuInfoList.stream().filter(item -> Objects.equals(GlobalErrorCodeEnum.PRODUCT_DOWN.getCode(),item.getState())).map(OrderTO.ErrorSkuInfo::getSkuCode).collect(Collectors.toList());
				if(CollectionUtils.isNotEmpty(offShelfSkuCodeList)) {
					productCenterApiClient.offShelfProducts(offShelfSkuCodeList);
				}
				return OrderTO.builder().success(Boolean.FALSE).errorSkuInfoList(errorSkuInfoList).build();
			} else {
				OrderSubmitBO.ErrorOrderInfo singleData = SupplyCollectionUtils.getSingleDataFirst(orderSubmit.getErrorOrderList());
				CustomAssert.isTrue(false,singleData.getErrorCode(),singleData.getErrorMessage(),singleData.getErrorData());
			}
		}
		String supplyTradeSn = orderService.submitOrderSave(orderSubmit, submitOrder);
		return OrderTO.builder().success(Boolean.TRUE).supplyTradeSn(supplyTradeSn).build();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean confirmOrder(ConfirmOrderDTO confirmOrder) {
		CustomAssert.isTrue(confirmOrder.check(),"参数不合法");

		OrderStatusCheckBO orderStatusCheck = new OrderStatusCheckBO();
		orderStatusCheck.setOrderSnList(confirmOrder.getOrderSnList());
		orderStatusCheck.setSupplyTradeSn(confirmOrder.getSupplyTradeSn());
		orderStatusCheck.setCheckStatusList(Lists.newArrayList(OrderStatusEnum.WAIT_PAY.getValue()));

		List<OrderInfoBO> orderInfoList = orderService.checkOrderStatus(orderStatusCheck);
		//订单号集合
		List<String> orderSnList = orderInfoList.stream().map(OrderInfoBO::getOrderSn).collect(Collectors.toList());
		//获取订单商品信息
		List<OrderProductBO> orderProductList = orderProductService.listOrderProductInfo(orderSnList);
		//增加销量
		List<SalesVolumeStatistics.OrderSalesVolumeStatistics> orderSalesVolumeStatisticsList = orderInfoList.stream().map(order -> {
			List<OrderProductBO> orderProducts = orderProductList.stream().filter(e -> Objects.equals(order.getOrderSn(), e.getOrderSn())).collect(Collectors.toList());
			return Optional.of(orderProducts).orElse(Lists.newArrayList()).stream().map(orderProduct -> {
				SalesVolumeStatistics.OrderSalesVolumeStatistics volumeStatistics = new SalesVolumeStatistics.OrderSalesVolumeStatistics();
				volumeStatistics.setOrderNum(orderProduct.getSkuNum());
				volumeStatistics.setBackOrderNum(CommonConstants.ZERO);
				volumeStatistics.setOrderSn(orderProduct.getOrderSn());
				volumeStatistics.setSkuCode(orderProduct.getSkuCode());
				return volumeStatistics;
			}).collect(Collectors.toList());
		}).flatMap(Collection::stream).collect(Collectors.toList());
		applicationContext.publishEvent(new SalesVolumeStatistics(orderSalesVolumeStatisticsList));
		orderService.updateStatusByOrderSnList(orderSnList, OrderStatusEnum.RECHARGE, OrderStatusEnum.WAIT_PAY, OperateSourceConstants.OPERATION_BUSINESS, OrderOperateConstants.BUSINESS_ORDER_CONFIRM_SUCCESS,null);
		// 发送确认订单消息
		supplyChainMQProducer.orderConfirmSend(confirmOrder.getSupplyTradeSn(), orderSnList);
		return Boolean.TRUE;
	}

	@Override
	public Boolean confirmReceive(ConfirmReceiveDTO confirmReceive) {
		OrderStatusCheckBO orderStatusCheck = new OrderStatusCheckBO();
		orderStatusCheck.setOrderSnList(confirmReceive.getOrderSnList());
		orderStatusCheck.setCheckStatusList(Lists.newArrayList(OrderStatusEnum.SHIPPED.getValue()));
		List<OrderInfoBO> orderInfoList = orderService.checkOrderStatus(orderStatusCheck);
		List<String> orderSnList = orderInfoList.stream().map(OrderInfoBO::getOrderSn).collect(Collectors.toList());
		orderService.updateStatusByOrderSnList(orderSnList,
				OrderStatusEnum.SHIPPED,
				OrderStatusEnum.COMPLETE,
				OperateSourceConstants.OPERATION_BUSINESS,
				OrderOperateConstants.BUSINESS_ORDER_CONFIRM_SUCCESS,
				null);
		return Boolean.TRUE;
	}

	@Override
	public List<CancelOrderTO> cancelOrder(CancelOrderDTO cancelOrder) {
		CustomAssert.isTrue(cancelOrder.check(),"参数不合法");

		OrderStatusCheckBO orderStatusCheck = OrderStatusCheckBO.builder()
				.checkStatusList(Lists.newArrayList(OrderStatusEnum.WAIT_PAY.getValue(), OrderStatusEnum.WAIT_SHIP.getValue(), OrderStatusEnum.CANCEL.getValue()))
				.build();
		String supplyTradeSn = cancelOrder.getSupplyTradeSn();
		orderStatusCheck.setOrderSnList(cancelOrder.getOrderSnList());
		orderStatusCheck.setSupplyTradeSn(supplyTradeSn);
		List<OrderInfoBO> orderInfoList = orderService.checkOrderStatus(orderStatusCheck);
		List<CancelOrderTO> cancelOrderResult = orderInfoList.stream().filter(o -> EnumUtils.eq(OrderStatusEnum.CANCEL, o.getOrderStatus()))
				.map(e -> CancelOrderTO.builder()
						.orderSn(e.getOrderSn())
						.supplyTradeSn(e.getSupplyTradeSn())
						.orderStatus(e.getOrderStatus())
						.build()
				).collect(Collectors.toList());
		Map<Integer, List<OrderInfoBO>> orderStatusGroup = orderInfoList.stream().collect(Collectors.groupingBy(OrderInfoBO::getOrderStatus));
		List<OrderInfoBO> waitPayOrders = orderStatusGroup.get(OrderStatusEnum.WAIT_PAY.getValue());
		List<OrderInfoBO> waitShipOrders = orderStatusGroup.get(OrderStatusEnum.WAIT_SHIP.getValue());
		if (CollectionUtils.isNotEmpty(waitShipOrders)) {
			// 待发货状态取消必须要等待渠道确认完成
			List<String> collect = orderInfoList.stream().filter(item -> !orderService.channelConfirmCompleted(item)).map(OrderInfoBO::getOrderSn).collect(Collectors.toList());
			CustomAssert.notEmpty(collect, "暂不支持取消操作,请稍后再试或联系客服", collect);
		}
		if (CollectionUtils.isNotEmpty(waitPayOrders)) {
			List<String> orderSnList = waitPayOrders.stream().map(OrderInfoBO::getOrderSn).collect(Collectors.toList());
			log.info("待支付状态取消, supplyTradeSn:{}, orderSnList:{}", supplyTradeSn, JSON.toJSONString(orderSnList));
			orderService.updateStatusByOrderSnList(orderSnList, OrderStatusEnum.CANCEL, OrderStatusEnum.WAIT_PAY, OperateSourceConstants.OPERATION_BUSINESS, OrderOperateConstants.BUSINESS_CANCEL,null);
			supplyChainDelayMessageProducer.channelOrderCancelSend(supplyTradeSn, orderSnList, OrderStatusEnum.WAIT_PAY.getValue());
			List<CancelOrderTO> cancelOrderList = waitPayOrders.stream().map(item -> CancelOrderTO.builder()
					.orderSn(item.getOrderSn())
					.supplyTradeSn(item.getSupplyTradeSn())
					.orderStatus(OrderStatusEnum.CANCEL.getValue())
					.build()
			).collect(Collectors.toList());
			cancelOrderResult.addAll(cancelOrderList);
		}
		if (CollectionUtils.isNotEmpty(waitShipOrders)) {
			List<String> orderSnList = waitShipOrders.stream().map(OrderInfoBO::getOrderSn).collect(Collectors.toList());
			log.info("待发货状态取消, supplyTradeSn:{}, orderSnList:{}", supplyTradeSn, JSON.toJSONString(orderSnList));
			orderService.updateStatusByOrderSnList(orderSnList, OrderStatusEnum.CANCELLING, OrderStatusEnum.WAIT_SHIP, OperateSourceConstants.OPERATION_BUSINESS, OrderOperateConstants.BUSINESS_CANCEL,null);
			supplyChainMQProducer.cancelOrderApplySalesSend(supplyTradeSn, orderSnList);
			List<CancelOrderTO> cancelOrderList = waitShipOrders.stream().map(item -> CancelOrderTO.builder()
					.orderSn(item.getOrderSn())
					.supplyTradeSn(item.getSupplyTradeSn())
					.orderStatus(OrderStatusEnum.CANCELLING.getValue())
					.build()
			).collect(Collectors.toList());
			cancelOrderResult.addAll(cancelOrderList);
		}
		return cancelOrderResult;
	}

	@Override
	public List<OrderDetailTO> queryOrder(OrderQueryDTO orderQuery) {
		CustomAssert.isTrue(StringUtil.isNotBlank(orderQuery.getBizTradeSn()) || StringUtil.isNotEmpty(orderQuery.getSupplyTradeSn()) || CollectionUtils.isNotEmpty(orderQuery.getOrderSnList()), "参数不能为空");
		OrderQueryInBO orderQueryIn = OrderQueryInBO.builder().bizTradeSn(orderQuery.getBizTradeSn())
				.supplyTradeSn(orderQuery.getSupplyTradeSn())
				.orderSnList(orderQuery.getOrderSnList())
				.returnProduct(Boolean.TRUE)
				.returnLogistics(Boolean.TRUE)
				.returnConsignee(Boolean.TRUE)
				.build();
		List<OrderBO> orderList = orderService.list(orderQueryIn);

		// 有补单中标记的订单对业务方展示为待发货
		orderList.stream().filter(item -> OrderTagEnum.isRepairing(item.getOrderTag())).forEach(item -> {
			if (EnumUtils.eq(OrderTypeEnum.REAL_ORDER, item.getOrderType())) {
				item.setOrderStatus(OrderStatusEnum.WAIT_SHIP.getValue());
			} else {
				item.setOrderStatus(OrderStatusEnum.RECHARGE.getValue());
			}
		});
		// 人工处理状态对外展示为处理中
		orderList.stream().filter(item -> EnumUtils.eq(OrderStatusEnum.MANUAL_HANDLING, item.getOrderStatus())).forEach(item -> item.setOrderStatus(OrderStatusEnum.RECHARGE.getValue()));

		// 按照供应链三方交易单号分组
		Map<String, List<OrderBO>> orderTradeSnMap = orderList.stream().collect(Collectors.groupingBy(OrderBO::getOrderTradeSn));
		List<OrderDetailTO> mainOrderDetailToList = new ArrayList<>();
		orderTradeSnMap.forEach((orderTradeSn,list)->{
			List<OrderDetailTO> orderDetailList = orderConverter.toOrderDetailList(list);

			// 计算退款比例
			for (OrderDetailTO orderDetail : orderDetailList) {
				if (EnumUtils.eq(OrderStatusEnum.PART_SUCCESS, orderDetail.getOrderStatus())) {
					List<OrderDetailTO.OrderProductTO> orderProductList = orderDetail.getOrderProductList();
					for (OrderDetailTO.OrderProductTO orderProduct : orderProductList) {
						BigDecimal receivedPercentage = BigDecimal.ZERO;
						BigDecimal refundPercentage = BigDecimal.ZERO;
						// 返回给业务退款百分比
						if (Objects.nonNull(orderProduct.getActualAmount())) {
							receivedPercentage = NumberUtil.div(orderProduct.getActualAmount(), orderProduct.getOriginalPrice(), CommonConstants.FOUR, RoundingMode.HALF_UP);
							refundPercentage = BigDecimal.ONE.subtract(receivedPercentage);
						}
						orderProduct.setRefundPercentage(refundPercentage);
						orderProduct.setReceivedPercentage(receivedPercentage);
					}

				}
			}

			//进行数据组装
			OrderDetailTO mainOrderDetail = orderDetailList.stream().filter(item -> EnumUtils.eq(OrderLevelEnum.CHANNEL_MASTER_ORDER, item.getOrderParentSn())).findFirst().orElse( new OrderDetailTO());
			CustomAssert.notNull(mainOrderDetail, "订单数据异常");
			mainOrderDetailToList.add(mainOrderDetail);
			List<OrderDetailTO> subOrderDetailToList = orderDetailList.stream().filter(item -> EnumUtils.neq(OrderLevelEnum.CHANNEL_MASTER_ORDER, item.getOrderParentSn()) && EnumUtils.eq(OrderParentTypeEnum.AFTER_SPLIT, item.getParentType())).collect(Collectors.toList());
			if (CollectionUtils.isEmpty(subOrderDetailToList)) {
				//如果没有子单则copy主单给订单中心
				OrderDetailTO copy = orderConverter.copy(mainOrderDetail);
				couponInfoBuild(copy);
				mainOrderDetail.setSubOrderDetailList(Collections.singletonList(copy));
			} else {
				//TODO 为了适配以前的逻辑,暂时适配,后续调整的则删除此逻辑
				for (OrderDetailTO orderDetail : subOrderDetailToList) {
					couponInfoBuild(orderDetail);
				}
				mainOrderDetail.setSubOrderDetailList(subOrderDetailToList);
			}
		});
		return mainOrderDetailToList;
	}


	private void couponInfoBuild(OrderDetailTO orderDetail) {
		orderDetail.setOrderParentSn(orderDetail.getOrderSn());
		List<OrderDetailTO.OrderProductTO> orderProductList = orderDetail.getOrderProductList();
		List<OrderDetailTO.OrderProductTO> newOrderProductList = Lists.newArrayList();
		for (OrderDetailTO.OrderProductTO orderProduct : orderProductList) {
			if (ObjectUtils.isNotEmpty(orderProduct.getExtendInfo()) && CollectionUtils.isNotEmpty(orderProduct.getExtendInfo().getCouponInfos())) {
				List<OrderDetailTO.OrderProductTO.ExtendInfo.CouponInfo> couponInfoList = orderProduct.getExtendInfo().getCouponInfos();
				for (OrderDetailTO.OrderProductTO.ExtendInfo.CouponInfo couponInfo : couponInfoList) {
					OrderDetailTO.OrderProductTO orderProductTo = orderConverter.copyOrderProductTo(orderProduct);
					orderProductTo.setExtendInfo(OrderDetailTO.OrderProductTO.ExtendInfo.builder().couponInfoDetails(couponInfo).build());
					newOrderProductList.add(orderProductTo);
				}
			}else {
				return;
			}
		}
		orderDetail.setOrderProductList(newOrderProductList);
	}
}
